package fun.trackcam.source;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.Format;
import javax.media.MediaLocator;
import javax.media.NoDataSourceException;
import javax.media.control.FormatControl;
import javax.media.format.RGBFormat;
import javax.media.format.VideoFormat;
import javax.media.protocol.CaptureDevice;
import javax.media.protocol.DataSource;

import org.puzzle2.capture.Stdout;

public class DefaultCameraDao implements CameraDao {
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.puzzle4.source.CameraDao#createDataSource()
	 */
	public DataSource createDataSource(CaptureDeviceInfo captureVideoDevice,
			VideoFormat videoFormat) {
		// get a list of all media devices, search default devices and formats,
		// and print it out if args[x] = "-dd"
		// --------------------------------------------------------------------------------------------------------

		MediaLocator videoMediaLocator = captureVideoDevice.getLocator();
		DataSource videoDataSource = null;
		try {
			videoDataSource = javax.media.Manager
					.createDataSource(videoMediaLocator);
		} catch (IOException ie) {
			Stdout.logAndAbortException(ie);
		} catch (NoDataSourceException nse) {
			Stdout.logAndAbortException(nse);
		}

		if (!setFormat(videoDataSource, videoFormat)) {
			Stdout.log("Error: unable to set video format - program aborted");
			System.exit(0);
		}

		return videoDataSource;
	}

	/**
	 * @return List<CaptureDeviceInfo> list of all capture video format
	 *         avalaible
	 */
	public List<CaptureDeviceInfo> getAllCaptureVideoDevice() {
		List<CaptureDeviceInfo> result = new ArrayList<CaptureDeviceInfo>();
		Vector deviceListVector = CaptureDeviceManager.getDeviceList(null);
		if (deviceListVector == null || deviceListVector.size() == 0) {
			System.err.println("no video device");
			return null;
		}

		for (int x = 0; x < deviceListVector.size(); x++) {
			CaptureDeviceInfo captureDeviceInfo = (CaptureDeviceInfo) deviceListVector
					.elementAt(x);
			for (Format format : captureDeviceInfo.getFormats()) {
				if (format instanceof RGBFormat) {
					result.add(captureDeviceInfo);
					break;
				}
			}
		}
		return result;
	}

	public boolean setFormat(DataSource dataSource, Format format) {
		boolean formatApplied = false;

		FormatControl formatControls[] = null;
		formatControls = ((CaptureDevice) dataSource).getFormatControls();
		for (int x = 0; x < formatControls.length; x++) {
			if (formatControls[x] == null)
				continue;

			Format supportedFormats[] = formatControls[x].getSupportedFormats();
			if (supportedFormats == null)
				continue;

			if (formatMatches(format, supportedFormats) != null) {
				formatControls[x].setFormat(format);
				formatApplied = true;
			}
		}

		return formatApplied;
	}

	public Format formatMatches(Format format, Format[] supported) {
		if (supported == null)
			return null;
		for (int i = 0; i < supported.length; i++)
			if (supported[i].matches(format))
				return supported[i];
		return null;
	}

	/**
	 * @param captureDeviceInfo
	 * @return List<RGBFormat> list of all RGB video format avalaible for
	 *         captureDeviceInfo
	 */
	public List<RGBFormat> getAllRGBFormat(CaptureDeviceInfo captureDeviceInfo) {
		List<RGBFormat> result = new ArrayList<RGBFormat>();
		for (Format format : captureDeviceInfo.getFormats()) {
			if (format instanceof RGBFormat) {
				RGBFormat f = (RGBFormat) format;
				result.add(f);
			}
		}
		return result;
	}

}
